#include "func.h"
#include <stdlib.h>
#include <limits>
using namespace std;

double epsilon=numeric_limits<double>::epsilon();

class EquationSolver
{
 public:
  virtual double solve() = 0;//virtual
};

class Bisection : public EquationSolver
{
 private:
  double a;
  double b;
  double delta;
  int M;
  Function* f;
 public:
  Bisection(double _a, double _b, double _delta, int _M, Function* _f)
    {
      a=_a;
      b=_b;
      delta=_delta;
      M=_M;
      f=_f;
    }
  double solve();
};

double Bisection::solve()
{
  double h;
  double u;
  double c;
  double w;
  double a1;
  int k;
  a1=a;
  h=b - a;
  u=(*f)(a);
  for (k=1;k<=M;k++)
    {
      h=h/2;
      c=a1+h;
      w=(*f)(c);
      if (abs(h)<delta||abs(w) < epsilon )
	{
	  break;
	}
      else if (w*u>=0)
	{
	  a1=c;
	}
    }
  return c;
}

//Bisection bis(0,1,1e-10,func);
//bis.solve();

class Newton : public EquationSolver
{
 private:
  double x0;
  int M;
  Function* func;
 public:
    Newton(double _x0, int _M, Function* _func)
    {
      x0=_x0;
      M=_M;
      func=_func;
    }
  double solve();
};

double Newton::solve()
{
  double x;
  double u;
  x=x0;
  for(int k=0;k<=M;k++)
    {
      u=(*func)(x);
      if(abs(u) < epsilon )
	{
	  break;
	}
      x=x-u/(*func).diff(x);
    }
  return x;
}


//Newton new(0.1,10,func);
//new.solve();

class Secant : public EquationSolver
{
 private:
  double x0;
  double x1;
  double delta;
  int M;
  Function* f;
 public:
  Secant(double _x0, double _x1, double _delta, int _M, Function* _f)
    {
      x0=_x0;
      x1=_x1;
      delta=_delta;
      M=_M;
      f=_f;
    }
  double solve();
};

double Secant::solve()
{
  double xn;
  double xn_1;
  double u;
  double v;
  double c;
  double s;
  xn=x1;
  xn_1=x0;
  u=(*f)(xn);
  v=(*f)(xn_1);
  for(int k=2;k<=M;k++)
    {
      if(abs(u)>abs(v))
	{
	  c=xn;
	  xn=xn_1;
	  xn_1=c;
	  c=u;
	  u=v;
	  v=c;
	}
      s=(xn-xn_1)/(u-v);
      xn_1=xn;
      v=u;
      xn=xn-u*s;
      u=(*f)(xn);
      if(abs(xn-xn_1)<delta||abs(u)<epsilon)
	{
	  break;
	}
    }
  return xn;
}
